//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
/*
 * Blob Boot loader main
 */


#include "config.h"
#include "command.h"
#include "flash.h"
#include "serial.h"
#include "time.h"
#include "main.h"
#include "util.h"
//#include "uucodec.h"
#include "bulverde.h"
#include "net.h"
#include "smc91x.h"
#include "irq.h"
#include "xmodem.h"
#include "ymodem.h"
#include "mem.h"
#include "tat.h"
#include "version.h"
#include "crc16.h"
#include "usb_serial_download.h"
#include "pxa_usb.h"

/* simon */
#include "pcf50606.h"

/* ethan */

#include "bcm2121.h"
#include "KeypadTest.h"

#define TAT	1
#define USBDOWNLOADIMAGE 1

#define USBCHECKCON 1
#define NOKEYPAD    1
//#define FLASH

//The following is used to update the whole Image by USB

volatile int iimageupdate_by_usb=0;
#ifdef TAT
unsigned int run_mode;
unsigned int verbose_level = 1;
#endif
int version_no = BlobBootLoaderVersion;

extern int IdentifyDoc (void);
extern int FormatDoc();
extern int WriteIPL(int addr);
extern int WriteSPL(int addr);
extern int WriteLogo();
extern int ReadLogo();
extern int WriteKernel();
extern int LoadKernel(void *to);
extern int doc_info (void);
extern int WriteRootFs();
extern int WriteMMI();
extern int ShowLast512Byte();
extern int doc_read_rootfs();
extern int WriteTAT();
extern int ReadTAT();
extern int WriteTatTable(unsigned char *buff);
extern int ReadTatTable(unsigned char *buff);


extern void FastFlash(u32* dest, u32* source, u32 length);
extern int udownload_cmd(u32 *destAddress, u32 bufLen);
extern int UsbDownloadImageEx();
extern int md5_stream (char *start_address, int length);
void LoadKernelAndRamdisk(void);
void BootKernel(int arg0, int arg1);
void Download(u8* address);
void Jump(u32* address);
void JumptoTAT(void);
void PrintHelp(void);

void ResetTerminal(void);
void PrintSerialSpeed(eBauds speed);
void ExecuteCommand(u8* commandline);
void hw_reset(void);
int SplitRam(int addr, int nSize);
void ArmSys();

int g_bWrite = 1;

#ifdef TAT
unsigned char rts_signal;
int rts_try;
unsigned long rts_ack_timeout;
#endif


#define CCCR_ADDR	0x41300000

void ShowVersion(void);

void ChangeFreq(int l, int twoN, int turbo, int b)
{
	int value;
	volatile int *regT;

	regT = (volatile int *)CCCR_ADDR;
	value = *regT;
	value &= 0x3FFFFFFF; 				//make sure the Core and Peripheral PLL disable bits are clear.
	value = value & 0xFFFFF000;			//clear the L and 2N bits

	l = l & 0x1F;					//make sure L is only 0 thru 31
	value |= l; 					//OR in the L value

	twoN = twoN & 0xf;				//make sure 2N is only 0 thru 15
	value |= (twoN << 7);				//OR in the 2N value

	*regT = value;					//now set the CCCR register

	if (turbo==0 && b==0){
	__asm("mov	r0, #0x2");   	     		//set to Frequency Change Mode
	__asm("mcr	p14, 0, r0, c6, c0, 0");	//write to the CLKCFG coprocessor reg
	}

	if (turbo!=0 && b==0){
	__asm("mov	r0, #0x3");   	     		//set to Frequency Change Mode
	__asm("mcr	p14, 0, r0, c6, c0, 0");	//write to the CLKCFG coprocessor reg
	}

	if (turbo!=0 && b!=0){
	__asm("mov	r0, #0xB");   	     		//set to Frequency Change Mode
	__asm("mcr	p14, 0, r0, c6, c0, 0");	//write to the CLKCFG coprocessor reg
	}
}
/*
extern __bss_start;
extern __bss_end;
extern __text;
extern __etext;
extern __data;
extern __edata;
*/
extern unsigned int  __bss_start;
extern unsigned int  __bss_end;
extern unsigned int  __text;
extern unsigned int  __etext;
extern unsigned int  __data;
extern unsigned int  __edata;

void show_symbol_addr(void)
{
	printk("Test \n");
	printk("_text      : %x\n", (unsigned int *)&__text);
	printk("_etext     : %x\n", (unsigned int *)&__etext);
	printk("_data      : %x\n", (unsigned int *)&__data);
	printk("_edata     : %x\n", (unsigned int *)&__edata);
	printk("_bss_start : %x\n", (unsigned int *)&__bss_start);
	printk("_bss_end   : %x\n", (unsigned int *)&__bss_end);
}

void test_bss_data(void)
{
	static unsigned int abc = 0xABCD;

	printk("%x should be 0xabcd when it's called first\n", abc);
	abc++;
}

void ShowUsbPinState(void)
{
	printk("GPIO40 (B_USB_FULLSPEED) : Dir(%d), Level(%d), Alt(%d) \n", (GPDR1 & 0x00000100) ? 1 : 0, (GPLR1 & 0x00000100) ? 1 : 0, (GAFR1_L & 0x00030000) >> 16 );
	printk("GPIO38 (B_OTG_PWREN    ) : Dir(%d), Level(%d), Alt(%d) \n", (GPDR1 & 0x00000040) ? 1 : 0, (GPLR1 & 0x00000040) ? 1 : 0, (GAFR1_L & 0x00003000) >> 12);
	printk("GPIO35 (B_USB_DEC_N    ) : Dir(%d), Level(%d), Alt(%d) \n", (GPDR1 & 0x00000008) ? 1 : 0, (GPLR1 & 0x00000008) ? 1 : 0, (GAFR1_L & 0x000000C0) >> 6);
	printk("GPIO41 (B_OTG_ID       ) : Dir(%d), Level(%d), Alt(%d) \n", (GPDR1 & 0x00000200) ? 1 : 0, (GPLR1 & 0x00000200) ? 1 : 0, (GAFR1_L & 0x000C0000) >> 18);
	printk("GPIO22 (B_OTG_PWRFLG   ) : Dir(%d), Level(%d), Alt(%d) \n", (GPDR0 & 0x00400000) ? 1 : 0, (GPLR0 & 0x00400000) ? 1 : 0, (GAFR0_U & 0x00003000) >> 12);
}

void c_main(void)
{

#ifdef TAT
	int i;
	unsigned int crc16;
#endif
	unsigned char commandline[128] = {0,};
	int retval = 0;
#ifdef TAT
//	unsigned int gpdr0, gafr0_u;
	int ret;
#endif
	/* __REG(GPIO_BASE_PHYSICAL+GAFR0_U_OFFSET) = 0x59e5404e; */
        /* __REG(GPIO_BASE_PHYSICAL+GPLR0_OFFSET)   = 0x20000; */
        /* __REG(GPIO_BASE_PHYSICAL+GPDR0_OFFSET)   = 0x20000; */
        /* __REG(GPIO_BASE_PHYSICAL+GPSR0_OFFSET)   = 0x28800; */

	/* __REG(GPIO_BASE_PHYSICAL+GPCR0_OFFSET) |= 0x20000; */

	/* __REG(PWR_BASE_PHYSICAL+PSSR_OFFSET)     |= (PCFR_GPR_EN | PCFR_SYSEN_EN); */

	/* SerialInit(baud115k2); */
	/* SerialOutputByte('a'); */

	/*change frequence to 312/208/104 turbo mode */
	/* Some board doesn't work at high speed */
	ChangeFreq(16, 3, 1, 1);	/* 16 * 13MHz = 208 Mhz Turbo-Mode */
	SerialInit(baud115k2);
	TimerInit();/* this should be done before net_init */
	pcf50606_init();
#if 0
	Xs_LCD_Init();
	Display_Logo();
#endif

#if 0	/* Test Data segment and BSS segment */
	show_symbol_addr();
	test_bss_data();
	test_bss_data();
#endif

	/* Turn On Charger LED P2 Board Only */
#ifdef P2_BOZARD
//	*(unsigned int *)(GPIO_BASE_PHYSICAL + GPSR3_OFFSET) = 0x01000000;
#endif

	/* while(1) */
	/* { */
	/* 	u32 rcnr_val =  __REG (RTC_BASE_PHYSICAL+RCNR_OFFSET); */
	/* 	printk("rcnr_val------%d\n", rcnr_val); */
	/* } */


	//printk("### 1 [jiffies : %d]\n", jiffies /* TimerGetTime() */);

#ifdef TAT

	rts_ack_timeout = 5;

	run_mode = KERNEL_MODE;
	{
//	printk("Bill: The following is the key test\n");
	int key;
//	int iloop=0;
	wls_keypad_init();
//	for(iloop=0;iloop<10;iloop++)
		{
			key=wls_keypad_getkey();
//			printk("Bill: key=%d\n", key);
#if 0
			if(key==32)
				{iimageupdate_by_usb=1; /*break;*/}
#endif
			if(key==32) {
                UsbDownloadImage();
            } else if (key == 46) {
		        g_bWrite = 0;
		        if (UsbDownloadImageEx()) {
		            g_bWrite = 1;
			        BootKernel(BOOT_ARG0, BOOT_ARG1);
		        }
	        } else if (key == 30) {
	            ExecuteCommand((u8*)"formatdoc");
                UsbDownloadImage();
            }

		}
	}//end of the local function
#if 1
    if (!SerialInputBlock_msec((char*)commandline,  1, 10)) {
        ArmSys();
    }
#endif
//Here the USB interrupt will clear it!
#if 0
	if(iimageupdate_by_usb)
	{
	while(iimageupdate_by_usb);
	printk("Bill: -- The following is UsbDownloadImage\n");
		UsbDownloadImageEx();
	}
#endif
//
//The above is modified by Bill Chen

	for(i = 0; i < 3; i++) {

		rts_signal = 0xAA; rts_try = i;

		SerialOutputByte(rts_signal);
		retval = SerialInputBlock_msec((char*)commandline,  1, rts_ack_timeout); /* 1 jiffie = 10 milli-sec */
		if( retval >= 1 ) {
			if( (commandline[0] == 0xa1) || (commandline[0] ==0x64)) { /* d */

				/* Jump to linux kernel */
				SerialOutputString("Bulverde download mode");
				run_mode = BULVERDE_DOWNLOAD_MODE;
				break;
			} else
			if( (commandline[0] == 0xa2) || (commandline[0] == 0x67) ) { /* g */

				/* Jump to linux kernel */
				SerialOutputString("modem download mode");
			#if 0
				/* Set B_UART_SW pin in high state so as to enable uart connection btw modem and PC */
				gpdr0 = __REG(GPIO_BASE_PHYSICAL + GPDR0_OFFSET);
				*(unsigned int *)(GPIO_BASE_PHYSICAL + GPDR0_OFFSET) = gpdr0 | (0x01 << 26);

				*(unsigned int *)(GPIO_BASE_PHYSICAL + GPSR0_OFFSET) =  (0x01 << 26);

				gafr0_u = __REG(GPIO_BASE_PHYSICAL + GAFR0_U_OFFSET);
					*(unsigned int *)(GPIO_BASE_PHYSICAL + GAFR0_U_OFFSET) = gafr0_u & ~(GPIO_26_AF3);
				run_mode = MODEM_DOWNLOAD_MODE;
			#endif
				bcm2121_imagedownload(0x10000, 0x2113b8, 115);
				break;
			} else
			if( (commandline[0] == 0xa3) || (commandline[0] == 0x74) ) { /* t */

				/* Jump to TAT application */
				SerialOutputString("Jump to TAT mode");

				run_mode = TAT_MODE;

				/*
				cli();
				JumptoTAT();
				*/
			#ifdef TAT
				//tat_menu();
			#endif
			} else
			if( (commandline[0] == 0xa4) || (commandline[0] == 0x62) ) { /* b */

				/* Jump to boot-loader command-mode */
				/*SerialOutputString("Jump to boot-loader command-mode");*/
				run_mode = BOOTLOADER_MODE;
				verbose_level = 1;
				break;
			} else {

				/* Jump to kernel */
				SerialOutputString("Jump to boot-up kernel\n");
				run_mode = KERNEL_MODE;
				verbose_level = 1;
				break;
			}
		} else {
			/* Time-Out */
			rts_ack_timeout += 5;	/* Increase time-out 50 ms in every failure */
		}
	}
#endif	/* End of TAT definition */


	/*printk("### 2 [jiffies : %d]\n", jiffies);

	printk("\n\nBlob Boot Loader for " TARGET_MACHINE " " VERSION "\n"
		  "Copyright (C) 2004. \n\n");*/

	/*
         * display a logo
         */
     /* pcf50606_led2_on(); */
/* //   logo_display(); */
	/* run_mode = BOOTLOADER_MODE; */

	/* wait 3 seconds before starting autoboot */
	/* printk("Autoboot in progress, press any key to stop\n"); */

	/* Unlock the flash regions excepts BootLoader regions */
	/* printk("#########################################\n"); */
	/* printk("Unlock the flash excepts Parameter Blocks\n"); */
	/* cli(); */
	/* FlashUnlockBlocks((FLASH_PTR_t)0x00020000, 0x01FE0000); */
	/* sti(); */
	/* printk("#########################################\n\n"); */

#if 0
	ShowUsbPinState();
#endif

#ifdef USBDOWNLOADIMAGE
	/*printk("### 3 [jiffies : %d]\n", jiffies);*/

	/* #ifdef NOKEYPAD */
	/* UsbDownloadImage(); */
	/* #endif */

	if( run_mode == KERNEL_MODE ){
		int key;
		wls_keypad_init();
		key = wls_keypad_getkey();
		switch( key ){
		case 0x19:	// Key F1
			UsbDownloadImageEx();
			break;
		case 0x13:	// Key running
			bcm2121_download2pc();
			break;
		default:
                        break;
		}
	}
#endif //USBDOWNLOADIMAGE

	/* no key was pressed, so proceed booting the kernel */
	if( run_mode == KERNEL_MODE ) {
		commandline[0] = '\0';
		/*printk("### 4 [jiffies : %d]\n", jiffies);*/
		printk("\nAuto Boot Entered\n");
		if (LoadKernel((void*)KERNEL_RAM_START)) {
		    /* LoadKernelAndRamdisk();	/\* takes about 150 ms for 1MB *\/ */
		    /*printk("### 5 [jiffies : %d] loaded linux kernel into memory \n", jiffies);*/
		    cli();
		    BootKernel(BOOT_ARG0, BOOT_ARG1);
		}


	}

	ShowVersion();
	printk("Type \"help\" to get a list of commands\n");

#ifdef TAT
	if( run_mode == BULVERDE_DOWNLOAD_MODE )
		verbose_level = 0;  /* No messages to console */
#endif

	/* the command loop. endless, of course */
	for(;;) {

		DisplayPrompt("\nEldr>");

		ret = GetCommand(( char *)commandline, 128, 3600);
		if( ret > 0 ) {
			ExecuteCommand((u8*)commandline); /* parse and execute the input */
		} else if( ret == 0 && (commandline[0] == '\n' || commandline[0] == '\r') ) {
			SerialOutputByte('\n');
		}

		if( run_mode == BULVERDE_DOWNLOAD_MODE ) {

			if( ret > 0 ) {
				crc16 =  crc16_ccitt((const void*)commandline,  (int)MyStrLen((const char *)commandline));
				SerialOutputRawByte(crc16 & 0xFF);    /* Low Byte first */
				SerialOutputRawByte((crc16 >> 8)& 0xFF);
			}
		}
	}
}

void ShowVersion()
{
#define BOOTLOADVERSION "1.1.0"
	printk( "\n\tElastos2.0 Bootloader\n\tVersion:%s, Time Stamp:%s\n", BOOTLOADVERSION, COMPILE_TIME_STAMP );
}

/*
  Parse and execute a command line
*/
void ExecuteCommand(u8* commandline)
{
  int ReadLocation=0;
  int NextReadLocation=0;
  u32 ReadValue[3];
  int ParseResult[3];
  u8 FileName[128];

	if(MyStrCmp((const char *)commandline,  (const char *)"elastos", 7)) {
		ReadLocation = 7;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		if((ParseResult[0]!=1)||(ParseResult[1]!=1)) {
			ReadValue[0] = BOOT_ARG0;
			ReadValue[1] = BOOT_ARG1;
		}
		cli();
		//LoadKernelAndRamdisk();
		LoadKernel ((void*)KERNEL_RAM_START);
		printk("begin boot kernel!\n");
		BootKernel(ReadValue[0], ReadValue[1]);
	} else if(MyStrCmp((const char *)commandline,  (const char *)"identifydoc", 11)){
	        IdentifyDoc();
	} else if(MyStrCmp((const char *)commandline,  (const char *)"formatdoc", 9)){
	        if(!FormatDoc())
			    printk("Format DiskOnChip Failed!\n");
	        else {
                int splAddr;
			    printk("Format DiskOnChip Successful!\n");
                MyMemCpyChar((u8*)RAM_START, (u8*)0xA3C00000, 0x80000);
		        if (splAddr = SplitRam(RAM_START, 0x80000)){
		    	    if(!WriteIPL(RAM_START)) {
		        	    printk("Write IPL Failed!\n");
		    		    return;
		    	    }
		    	    else
		        	    printk("Write IPL Successful!\n");

		    	    if(!WriteSPL(splAddr)) {
		    		    printk("Write SPL Failed!\n");
		    		    return;
		    	    }
		    	    else
		    		    printk("Write SPL Successful!\n");
		        }
		        else
		    	    printk("Update Loader Failed\n");
            }
	} else if(MyStrCmp((const char *)commandline,  (const char *)"udl", 3)){
		int splAddr;
		int nSize;
		printk("Download loader by Xmodem:");
		nSize = XModemReceive(( char *)RAM_START);
		if (nSize != -1) {
		    if ( (splAddr = SplitRam(RAM_START, nSize) ) != 0) {
		    	if(!WriteIPL(RAM_START)) {
		        	printk("Write IPL Failed!\n");
		    		return;
		    	}
		    	else
		        	printk("Write IPL Successful!\n");

		    	if(!WriteSPL(splAddr)) {
		    		printk("Write SPL Failed!\n");
		    		return;
		    	}
		    	else
		    		printk("Write SPL Successful!\n");
		    }
		    else
		    	printk("Update Loader Failed\n");
		} else
			printk("Download Loader Failed");
	} else if(MyStrCmp((const char *)commandline,  (const char *)"writekernel", 11)){
		if(!WriteKernel())
			printk("Write Kernel Failed!\n");
		else
			printk("Write Kernel Successful!\n");
	} else if(MyStrCmp((const char *)commandline,  (const char *)"loadkernel", 10)){
		if(!LoadKernel((void*)KERNEL_RAM_START))
			printk("Load Kernel Failed!\n");
		else
			printk("Load Kernel Successful!\n");
	} else if(MyStrCmp((const char *)commandline,  (const char *)"docinfo", 7)){
		doc_info();
	} else if(MyStrCmp((const char *)commandline,  (const char *)"showlast512", 11)){
		ShowLast512Byte();
	} else if(MyStrCmp((const char *)commandline,  (const char *)"writerootfs", 11)){
		WriteRootFs();
	} else if(MyStrCmp((const char *)commandline,  (const char *)"ldrrootfs", 9)){
		doc_read_rootfs();
	} else if(MyStrCmp((const char *)commandline,  (const char *)"writemmi", 8)){
		WriteMMI();
	} else if(MyStrCmp ((const char *)commandline,  (const char *)"usbdn", 5)){
		UsbDownloadImageEx();
	} else if(MyStrCmp ((const char *)commandline,  (const char *)"writetat", 8)){
		WriteTatTable((unsigned char*)(0xa0000000)) ;
	} else if(MyStrCmp ((const char *)commandline,  (const char *)"readtat", 7)){
		ReadTatTable((unsigned char*)(0xa0000000));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"writelogo", 9)){
		WriteLogo();
	} else if(MyStrCmp((const char *)commandline,  (const char *)"readlogo", 8)){
		ReadLogo();
	} else if(MyStrCmp((const char *)commandline,  (const char *)"keytest", 7)){
		keyTest();
	/* } else if(MyStrCmp((const char *)commandline,  (const char *)"vibrator_on", 11)){ */
	/* 	Enable_Vibrator(); */
	/* } else if(MyStrCmp (commandline,  (const char *)"vibrator_off", 12)){ */
	/* 	Disable_Vibrator(); */
	}
#ifdef FLASH
	else if(MyStrCmp((const char *)commandline,  (const char *)"bl_flash", 8)){
		ReadLocation = 8;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));

		if((ParseResult[0]==1)&&(ParseResult[1]==1)){
			if((u32)ParseResult[1] > BL_FLASH_LENGTH) {
				printk("BootLoader Length can't exceed 0x%08X\n",BL_FLASH_LENGTH);
				return;
		}

		cli();
		FlashUnlockBlocks((FLASH_PTR_t)0x0, (u32)ReadValue[1]);
		Flash((u32*)0x0, (u32*)(ReadValue[0]), ReadValue[1]);
		FlashLockBlocks((FLASH_PTR_t)0x0, (u32)ReadValue[1]);
		sti();

#ifndef TAT
		printk("Reset your board.\n");
		while(1);
#endif

	} else
		printk("Error : Some arguments are missing.\n");

	}
#endif /* FLASH */
	 else if(MyStrCmp((const char *)commandline,  (const char *)"dn_b", 4)) {
		unsigned int address = RAM_START;
		Download((u8*)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"dn_k", 4)) {
		unsigned int address = RAM_START;
		Download((u8*)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"dn_r", 4)) {
		unsigned int address = RAM_START;
		Download((u8*)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"dn_c", 4)) {
		unsigned int address = RAM_START;
		Download((u8*)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"dn_u", 4)) {
		unsigned int address = RAM_START;
		Download((u8*)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"dn_t", 4)) {
		unsigned int address = RAM_START;
		Download((u8*)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"dn_i", 4)) {
		unsigned int address = RAM_START;
		Download((u8*)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"dn", 2)){
		ReadLocation = 2;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		if(ParseResult[0]==1){
			Download((u8*)(ReadValue[0]));
		} else
			printk("Error : Some arguments are missing.\n");
	} else if(MyStrCmp((const char *)commandline,  (const char *)"dump", 4)){
		ReadLocation = 4;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)){
			DumpMem((u32*)(ReadValue[0]), ReadValue[1]);
		} else printk("Error : Some arguments are missing.\n");

	}
#ifdef FLASH
	else if(MyStrCmp((const char *)commandline,  (const char *)"flash ", 6)){
		ReadLocation = 6;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		ReadLocation+=NextReadLocation;
		ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)&&(ParseResult[2]==1)){
//			if(ReadValue[0] < (RAM_BOOT_LOADER_AREA_LENGTH/GetBlockSize((u16*)ReadValue[0])+1)*GetBlockSize((u16*)ReadValue[0])){
			if( (ReadValue[0]<(FLASH_BANK0_BASE+BL_FLASH_LENGTH))
				|| ReadValue[0] < (FLASH_BANK0_BASE+GetBlockSize((FLASH_PTR_t)ReadValue[0])) ) {
				printk("Error : Cannot write to boot loader area.\n");
				printk("        Use the bl_flash command.\n");
			} else{
				cli();
				Flash((u32*)(ReadValue[0]), (u32*)(ReadValue[1]), ReadValue[2]);
				sti();
			}
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_b", 4)) {
		char commandline[] = "bl_flash 0xa0000000 0x00020000";
		ExecuteCommand((u8*)commandline);

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fflash ", 7)){
		ReadLocation = 7;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		ReadLocation+=NextReadLocation;
		ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)&&(ParseResult[2]==1)){
//			if(ReadValue[0] < (RAM_BOOT_LOADER_AREA_LENGTH/GetBlockSize((u16*)ReadValue[0])+1)*GetBlockSize((u16*)ReadValue[0])){
			if( (ReadValue[0]<(FLASH_BANK0_BASE+BL_FLASH_LENGTH))
				|| ReadValue[0] < (FLASH_BANK0_BASE+GetBlockSize((FLASH_PTR_t)ReadValue[0])) ) {
				printk("Error : Cannot write to boot loader area.\n");
				printk("        Use the bl_flash command.\n");
			} else{
				cli();
				FastFlash((u32*)(ReadValue[0]), (u32*)(ReadValue[1]), ReadValue[2]);
				sti();
			}
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_k", 4)) {
		unsigned int flash_address = KERNEL_FLASH_START;
		unsigned int ram_address   = RAM_START;
		unsigned int image_length  = KERNEL_FLASH_LENGTH;
		cli();
		Flash((u32*)flash_address, (u32*)ram_address, (u32)image_length);
		sti();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_r", 4)) {
		unsigned int flash_address = ROOT_FLASH_START;
		unsigned int ram_address   = RAM_START;
		unsigned int image_length  = ROOT_FLASH_LENGTH;

		cli();
		Flash((u32*)flash_address, (u32*)ram_address, (u32)image_length);
		sti();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_u", 4)) {
		unsigned int flash_address = USER_FLASH_START;
		unsigned int ram_address   = RAM_START;
		unsigned int image_length  = USER_FLASH_LENGTH;

		cli();
		Flash((u32*)flash_address, (u32*)ram_address, (u32)image_length);
		sti();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_d", 4)) {
		unsigned int flash_address = USERDATA_FLASH_START;
		unsigned int ram_address   = RAM_START;
		unsigned int image_length  = USERDATA_FLASH_LENGTH;

		cli();
		Flash((u32*)flash_address, (u32*)ram_address, (u32) image_length );
		sti();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_t", 4)) {
		unsigned int flash_address = PTABLE_FLASH_START;
		unsigned int ram_address   = RAM_START;
		unsigned int image_length  = PTABLE_FLASH_LENGTH;

		cli();
		Flash((u32*)flash_address, (u32*)ram_address, (u32) image_length );
		sti();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_i", 4)) {
		unsigned int flash_address = INITIMAGE_FLASH_START;
		unsigned int ram_address   = RAM_START;
		unsigned int image_length  = INITIMAGE_FLASH_LENGTH;

		cli();
		FlashUnlockBlocks( (FLASH_PTR_t)flash_address, (u32)image_length);
		Flash((u32*)flash_address, (u32*)ram_address, (u32)image_length);
		FlashLockBlocks( (FLASH_PTR_t)flash_address, (u32)image_length);
		sti();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_status", 9)){
		ReadLocation = 9;
		cli();
		FlashStatus();
		sti();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_erase", 8)){
		ReadLocation = 8;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		if( (ParseResult[0]==1) && (ParseResult[1]==1) ) {
			cli();
			Fl_Erase( (FLASH_PTR_t)ReadValue[0], (u32)ReadValue[1] );
			sti();
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_lock", 7)){
		ReadLocation = 7;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		if( (ParseResult[0]==1) && (ParseResult[1]==1) ) {
			cli();
			FlashLockBlocks((FLASH_PTR_t)ReadValue[0],(u32)ReadValue[1]);
			sti();
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"fl_unlock", 9)){
		ReadLocation = 9;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		if( (ParseResult[0]==1)  && (ParseResult[1]==1) ) {
			cli();
			FlashUnlockBlocks((FLASH_PTR_t)ReadValue[0], (u32)ReadValue[1]);
			sti();
		} else printk("Error : Some arguments are missing.\n");

	}
#endif /* FLASH */
	else if(MyStrCmp((const char *)commandline,  (const char *)"help", 4)) {
		ReadLocation = 4;
		PrintHelp();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"jump", 4)){
		ReadLocation = 4;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		if((ParseResult[0]==1)){
			printk("Code will jump to "); DebugOutputHex(ReadValue[0]);
			cli();
			Jump((u32*)(ReadValue[0]));
			sti();
	    } else printk("Error : Some arguments are missing.\n");
#if 0
	} else if(MyStrCmp((const char *)commandline,  (const char *)"MACwrite", 8)){
		ReadLocation = 8;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		ReadLocation+=NextReadLocation;
		ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)&&(ParseResult[2]==1)){
			MACWrite((u16)(ReadValue[0]), (u16)(ReadValue[1]), (u16)(ReadValue[2]));
		} else printk("Error : Some arguments are missing.\n");
#endif
	} else if(MyStrCmp((const char *)commandline,  (const char *)"memcpy", 6)){
		ReadLocation = 6;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		ReadLocation+=NextReadLocation;
		ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)&&(ParseResult[2]==1)){
			MyMemCpyChar((u8*)(ReadValue[0]), (u8*)(ReadValue[1]), ReadValue[2]);
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"memcmp", 6)){
		ReadLocation = 6;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		ReadLocation+=NextReadLocation;
		ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)&&(ParseResult[2]==1)){
			CmpMem((ReadValue[0]), (ReadValue[1]), ReadValue[2]);
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"memset ", 7)){
		ReadLocation = 7;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		ReadLocation+=NextReadLocation;
		ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)&&(ParseResult[2]==1)){
			MyMemSetChar((u8*)(ReadValue[0]), (u8)(ReadValue[1]), ReadValue[2]);
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"memsetw", 7)){
		ReadLocation = 7;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		ReadLocation+=NextReadLocation;
		ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)&&(ParseResult[2]==1)){
			MyMemSet((u32*)(ReadValue[0]), (u32)(ReadValue[1]), ReadValue[2]);
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"ram_test", 8)){
		ReadLocation = 8;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)){
			ram_test((u32*)(ReadValue[0]), ReadValue[1]);
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"reset", 5)){
		ReadLocation = 5;
		hw_reset();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"ldr", 3)){
		ReadLocation = 3;
		ParseResult[0]=ParseFileName(commandline+ReadLocation, &NextReadLocation, FileName);
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)){
			load_memory((char*)FileName, (u32)ReadValue[0]);
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"str", 3)){
		ReadLocation = 3;
		ParseResult[0]=ParseFileName(commandline+ReadLocation, &NextReadLocation, FileName);
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)&&(ParseResult[2]==1)){
			store_memory((char*)FileName, (u32)ReadValue[0], (u32)ReadValue[1]);
    	} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"xdn_b", 5)) {
		unsigned int address = RAM_START;
		XModemReceive(( char *)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"xdn_k", 5)) {
		unsigned int address = RAM_START;
		XModemReceive(( char *)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"xdn_r", 5)) {
		unsigned int address = RAM_START;
		XModemReceive(( char *)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"xdn_c", 5)) {
		unsigned int address = RAM_START;
		XModemReceive(( char *)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"xdn_u", 5)) {
		unsigned int address = RAM_START;
		XModemReceive(( char *)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"xdn_t", 5)) {
		unsigned int address = RAM_START;
		XModemReceive(( char *)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"xdn_i", 5)) {
		unsigned int address = RAM_START;
		XModemReceive(( char *)(address));
	} else if(MyStrCmp((const char *)commandline,  (const char *)"xdn ", 4)) {
		ReadLocation = 4;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		if(ParseResult[0]==1){
			XModemReceive(( char *)(ReadValue[0]));
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"xup ", 4)) {
		ReadLocation = 4;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)){
			xmodemTransmit((u8*)ReadValue[0], ReadValue[1]);
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"udn ", 4)) {
		ReadLocation = 4;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)){
//			cli();
			udownload_cmd((u32 *)ReadValue[0], ReadValue[1]);
//			sti();
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"pmu_dump", 8)) {

		pcf50606_dump_registers();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"pmu_set", 7)){
		/* usage: pmu_set <power_name> <voltage_value> */
		/* 			- ex) pmu_set D1REG 11 */
		ReadLocation = 7;
		ParseResult[0]=ParseFileName(commandline+ReadLocation, &NextReadLocation, FileName);
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)){
			//load_memory(FileName, (u32)ReadValue[0]);
			pcf50606_pmu_set_voltage( FileName, ReadValue[0] );
		} else printk("Error : Some arguments are missing.\n");
#if 0
	/* simon, debugging purpose */
	} else if(MyStrCmp((const char *)commandline,  (const char *)"pmu_pm_regs", 11)) {
		pcf50606_dump_pm_registers();
#endif
	} else if(MyStrCmp((const char *)commandline,  (const char *)"md5sum", 6)){
		ReadLocation = 6;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		ReadLocation+=NextReadLocation;
		ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
		if((ParseResult[0]==1)&&(ParseResult[1]==1)){
			md5_stream((char*)&ReadValue[0], ReadValue[1]);
		} else printk("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"verbose", 7)) {
		ReadLocation = 7;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		if(ParseResult[0]==1){ /* input ok, now run the script */
			if( ReadValue[0] >= 1 )
				verbose_level = 2;
			else
				verbose_level = 0;
		} else SerialOutputString("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"halt", 4)) {
		ReadLocation = 4;
		ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
		if(ParseResult[0]==1){ /* input ok, now run the script */
			msleep(ReadValue[0]);	/* in ms */
		} else SerialOutputString("Error : Some arguments are missing.\n");

	} else if(MyStrCmp((const char *)commandline,  (const char *)"status", 6)){
		ReadLocation = 6;
		printk("jiffies       : %d\n", jiffies);
		printk("jiffies_div10 : %d\n", jiffies_div10);
		ShowUsbPinState();

	} else if(MyStrCmp((const char *)commandline,  (const char *)"version", 7)){
		ShowVersion();
/*	} else if (MyStrCmp((const char *)commandline,  (const char *)"logo1", 5)) {
                logo_display1();
	} else if (MyStrCmp((const char *)commandline,  (const char *)"logo", 4)) {
		Display_Logo();
*/	} else if(MyStrCmp((const char *)commandline,  (const char *)"bcm_on2pc",9)) {
		bcm2121_on2pc();
	} else if(MyStrCmp((const char *)commandline,  (const char *)"bcm_download2pc", 15)) {
		bcm2121_download2pc();
	} else if(MyStrCmp((const char *)commandline,  (const char *)"bcm_active",10)) {
		bcm2121_active();
	} else if(MyStrCmp((const char *)commandline,  (const char *)"bcm_inactive",12)) {
		bcm2121_inactive();
	} else if(MyStrCmp ((const char *)commandline,  (const char *)"u", 1)){
		g_bWrite = 0;
		if (UsbDownloadImageEx()) {
		    g_bWrite = 1;
			BootKernel(BOOT_ARG0, BOOT_ARG1);
		}
	} else {
		printk("*** Unknown command:  %s \n", commandline);
        PrintHelp();
	}
}

/*
  Jump to the pre-defined TAT in Flash
*/
void JumptoTAT(void)
{
	void (*theTAT)(void) = (void (*)(void))TAT_FLASH_START;
	theTAT();

	printk("Hey, the TAT returned! This should not happen.\r");
}


/*
  Jump to the pre-copied kernel in the RAM
*/
typedef struct BootInfo {
    unsigned int LoadAddress;
    unsigned int ImageBase;
    unsigned int ImageSize;
    unsigned int MemorySize;
    unsigned int WriteMagic;
    unsigned int Reserved1;
    unsigned int Reserved2;
    unsigned int Reserved3;
} BootInfo;

typedef struct PackageInfo {
    unsigned int    uReserved;
    void      		*modules;
    unsigned int    uNumberOfModules;
    unsigned int    uPackageSize;
    char      		*szCommandLine;
} PackageInfo;

void BootKernel(int arg0, int arg1)
{
	BootInfo *pLoadInfo = (BootInfo *)RAM_START;
	int	*pEntry;
	void (*theKernel)(int zero, int arch);
	// find kernel entry
	pEntry = (int*)(KERNEL_RAM_START + 0x3c);

	if ((*(int *)(*pEntry + KERNEL_RAM_START)) != 0x00004550) {
		printk("Kernel is not PE format!\n");
		return;
	}
	pEntry = (int*)(KERNEL_RAM_START + (*pEntry) + 0x28);
	theKernel = (void*)((*pEntry) + KERNEL_RAM_START);


	// set kernel arguments
	if (!arg1) {
		arg1 = (int)pLoadInfo;
		pLoadInfo->WriteMagic = 0;
		pLoadInfo->MemorySize = 0x4000000;
		pLoadInfo->LoadAddress = KERNEL_RAM_START;
		pLoadInfo->ImageBase = 0xc0020000;
		pEntry = (int*)(KERNEL_RAM_START + 0x8);
		pLoadInfo->ImageSize = ((PackageInfo *)(*pEntry + KERNEL_RAM_START))\
							 ->uPackageSize;
	}
/*	printk("loadinfo(%08x):WriteMagic%08x\n"
		   "MemorySize%08x\n"
		   "LoadAddress%08x\n"
		   "ImageBase%08x\n"
		   "ImageSize%08x\n",
		pLoadInfo,
		pLoadInfo->WriteMagic,
		pLoadInfo->MemorySize,
		pLoadInfo->LoadAddress,
		pLoadInfo->ImageBase,
		pLoadInfo->ImageSize);
*/
	printk("jump to kernel\n");
	cli();
	theKernel(arg0,arg1);
	sti();

	printk("Hey, the kernel returned! This should not happen.\r");
}

void Jump(u32* address)
{
	void (*Func)(void)= (void(*)(void))address;

	(*Func)();

	/* To return to this point, code should save every registes used,
	 * lr, etc. and return to the lr and should never modify the SP
	 */
}


void copy_block(unsigned int krn_start, unsigned int fl_start, unsigned int length)
{
	__asm__ volatile (
		"mov r0,%0      \n\
		mov r1,%1      \n\
		mov r2,%2      \n\
		1: ldmia r1!, {r5 - r12}       \n\
		stmia r0!, {r5 - r12}  \n\
		sub r2, r2, #32        \n\
		cmp r2, #0     \n\
		bgt 1b"
		:
		: "r" (krn_start), "r" (fl_start), "r" (length)
		: "r0", "r1", "r2", "r5", "r6", "r7", "r8", "r9", "r11", "r12");
}


/*
 * copy the kernel Image and ramdisk from the flash to the ramdisk
 */
void LoadKernelAndRamdisk(void)
{
#if 0
	/* 520 ms for 1MB */
	char commandline[128];
	char *tmp;

	tmp = commandline;
	/* Kernel Image loading from Flash into RAM */
	tmp = "memcpy 0xa0208000 0x00040000 0x00100000\n";
	ExecuteCommand((u8*)tmp);
#elif 0
	/* 150 ms for 1MB */
	int i;
	unsigned int *dest, *src;

	dest = KERNEL_RAM_START;
	src = KERNEL_FLASH_START;

	for( i = 0; i < KERNEL_FLASH_LENGTH;  ) {
		*dest++ = *src++;
		i += sizeof(void *);
	}
#else
	copy_block(KERNEL_RAM_START, KERNEL_FLASH_START, KERNEL_FLASH_LENGTH);
	copy_block(0xa0000100, 0x1ee2000, 2); // ethan
#endif
}

void hw_reset(void)
{
	int start_time;
	start_time = TimerGetTime();
	while((TimerGetTime()-start_time) < 2);
	SerialInit(baud115k2);
	TimerInit();
//	net_init();
}

/*
  Serial download, not implemented yet
*/
void Download(u8* address)
{
	serial_load( address );  /* fill out here */
}

int SplitRam(int addr, int nSize)
{
	int desAddr = 0xa0100000;
	int noCpy;
	int i;

	if (nSize <= 0) {
		printk("no boot loader data\n");
		return 0;
	} else if (nSize > 0x80000) {
		printk("too large size\n");
		return 0;
	}

	noCpy = (nSize + 0x1ff) >> 9;
	noCpy = noCpy > 0x400? 0x400: noCpy;

	for (i = 0; i < noCpy; i++) {
		memcpy((void*)desAddr, (void*)addr, 0x200);
		desAddr += 0x200;
		memcpy((void*)desAddr, (void*)addr, 0x200);
		desAddr += 0x200;
		addr += 0x200;
	}

	return 0xa0100000;
}

void ArmSys()
{
    unsigned long packsize,flashoffset;
    unsigned long buffer = KERNEL_RAM_START;
    long IsWriteFlash;

    SerialOutputRawByte('0');
    SerialOutputRawByte('1');
    SerialOutputRawByte('2');
    SerialOutputRawByte('3');

    // Send query signal,ask for file length
    SerialOutputRawByte('?');

    //  Get file length nowait
    flashoffset = SerialInputDWordWithTimeout();
    packsize = SerialInputDWordWithTimeout();
    IsWriteFlash = packsize & 0x80000000;
    packsize = packsize & ~0x80000000;

    if (packsize) {    // get image from armsys

        // end ready signal
        SerialOutputRawByte('<');

        // receive the file data
        SerialInputBlock_msec((char*)buffer, packsize, 20*60*1000/*20 minutes*/);

        SerialOutputRawByte('>');

        // jump to run program if u don't need write flash
        if (IsWriteFlash) {
            if(!WriteKernel())
			    printk("Write Kernel Failed!\n");
			else
			    printk("Have written Kernel to DOC\n");
        }

        // image is already in the dram
        BootKernel(0, 0);
    }
}

void PrintHelp(void)
{
	printk("\nHelp for Elastos2.0 Bootloader:\n\n");
	printk("* elastos [arg0 arg1]  Boot Elastos2.0 with optional kernel options\n");
	printk("* udl                  Update bootloader by xmodem\n");
    printk("* usbdn                Download kernel image to RAM by USB\n");
    printk("                       and write to kernel partition on DOC\n" );
    printk("* u                    Download kernel image to RAM by USB and\n");
    printk("                       run into kernel\n" );
//	printk("* dn {add}             Download a file via yMODEM to the address of {add}\n");
//	printk("* dn_k                 Download kernel file via yMODEM\n");
	printk("* xdn {add}            Download a file via xMODEM to the address of {add}\n");
//	printk("* xdn_r                Download root file via xMODEM\n");
	printk("* docinfo              Infomation of DiskOnChip\n");
	printk("* formatdoc            Format DOC. NOTE: Update loader after formatdoc\n");
	printk("* writekernel          Write  Kernel\n");
	printk("* loadkernel           Load   Kernel\n");
	printk("* dump {add} {len}     Dump the contents of the memory\n");
	printk("* jump {add}           Brach to the given {add}\n");
	printk("* memset {add} {val} {len}\n");
	printk("                       Set the memory with given {val}\n");
	printk("* memcpy {dest_add} {source_add} {len}\n");
	printk("                       Copy memory from the source to the destination\n");
	printk("* memcmp {add1} {add2} {len}\n");
	printk("                       Compare contents of memory\n");
	printk("* ldr [-l : -h : -b] {add}\n");
	printk("                       Display [32:16:8]bits memory contents.\n");
	printk("* str [-l : -h : -b] {add} {val}\n");
	printk("                       Store [32:16:8]bits {val} on {add}\n");
	printk("* pmu_dump [reg_name]  Dump the contents of each pmu related register\n");
    printk("                       of pcf50606 chip.\n" );
	printk("* pmu_set <power_name> <voltage>\n");
	printk("                       power_name:<D1REG|D2REG|D3REG|DCD|DCDE|DCUD|IOREG|LPREG>\n" );
	printk("                       voltage: 9 ~ 55\n" );
//	printk("* writerootfs          Write  ROOTFS\n");
//	printk("* Writemmi             Write  MMI\n");
	printk("* bcm_on2pc            Power on BCM2121 and switch UART to PC\n");
	printk("* bcm_download2pc      Set BCM2121 to download mode and switch UART to PC\n");
	printk("* bcm_active           Wake BCM2121\n");
	printk("* bcm_inactive         Put BCM2121 into sleep mode\n");
	printk("* help                 Show this messages\n");
}

